home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / ghostscript / 8.64 / Resource / Init / pdf_base.ps < prev    next >
Encoding:
Text File  |  2009-04-17  |  39.3 KB  |  1,083 lines

  1. %    Copyright (C) 1994-2006 Artifex Software, Inc.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: pdf_base.ps 9338 2009-01-09 00:28:18Z ray $
  14. % pdf_base.ps
  15. % Basic parser for PDF reader.
  16.  
  17. % This handles basic parsing of the file (including the trailer
  18. % and cross-reference table), as well as objects, object references,
  19. % streams, and name/number trees; it doesn't include any facilities for
  20. % making marks on the page.
  21.  
  22. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  23. .currentglobal true .setglobal
  24. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  25. pdfdict begin
  26.  
  27. % Define the name interpretation dictionary for reading values.
  28. /valueopdict mark
  29.   (<<) cvn { mark } bind    % don't push an actual mark!
  30.   (>>) cvn { { .dicttomark } stopped {
  31.       (   **** File has an unbalanced >> \(close dictionary\).\n)
  32.       pdfformaterror
  33.     } if
  34.   } bind
  35.   ([) cvn { mark } bind        % ditto
  36.   (]) cvn dup load
  37. %  /true true        % see .pdfexectoken below
  38. %  /false false        % ibid.
  39. %  /null null        % ibid.
  40.   /F dup cvx        % see Objects section below
  41.   /R dup cvx        % see Objects section below
  42.   /stream dup cvx    % see Streams section below
  43. .dicttomark readonly def
  44.  
  45. % ------ Utilities ------ %
  46.  
  47. % Define a scratch string. The PDF language definition says that
  48. % no line in a PDF file can exceed 255 characters, but this string
  49. % is also used to search for %PDF-, which needs 1024 characters.
  50. /pdfstring 1024 string def
  51.  
  52. % Read the previous line of a file.  If we aren't at a line boundary,
  53. % read the line containing the current position.
  54. % Skip any blank lines.
  55. /prevline        % - prevline <startpos> <substring>
  56.  { PDFfile fileposition dup () pdfstring
  57.    2 index 257 sub 0 .max PDFfile exch setfileposition
  58.     {        % Stack: initpos linepos line string
  59.       PDFfile fileposition
  60.       PDFfile 2 index readline pop
  61.       dup length 0 gt
  62.        { 3 2 roll 5 -2 roll pop pop 2 index }
  63.        { pop }
  64.       ifelse
  65.         % Stack: initpos linepos line string startpos
  66.       PDFfile fileposition 5 index ge { exit } if
  67.       pop
  68.     }
  69.    loop pop pop 3 -1 roll pop
  70.  } bind def
  71.  
  72. % Handle the PDF 1.2 #nn escape convention when reading from a file.
  73. % This should eventually be done in C.
  74. /.pdffixname {            % <execname> .pdffixname <execname'>
  75.   PDFversion 1.2 ge {
  76.     dup .namestring (#) search {
  77.       name#escape cvn exch pop
  78.     } {
  79.       pop
  80.     } ifelse
  81.   } if
  82. } bind def
  83. /name#escape            % <post> <(#)> <pre> name#escape <string>
  84. { exch pop
  85.   1 index 2 () /SubFileDecode filter dup (x) readhexstring
  86.         % Stack: post pre stream char t/f
  87.   not {    % tolerate, but complain about bad syntax
  88.     pop closefile (#) concatstrings exch
  89.     (   **** Warning: Invalid hex following '#' name escape, using literal '#' in name.\n)
  90.     pdfformaterror
  91.   } {
  92.     exch closefile concatstrings
  93.     exch 2 1 index length 2 sub getinterval
  94.   } ifelse
  95.   (#) search { name#escape } if concatstrings
  96. } bind def
  97.  
  98. % Execute a file, interpreting its executable names in a given
  99. % dictionary.  The name procedures may do whatever they want
  100. % to the operand stack.
  101. /.pdftokenerror {        % <count> <opdict> <errtoken> .pdftokenerror -
  102.   BXlevel 0 le {
  103.     (   **** Unknown operator: ') pdfformaterror
  104.     dup =string cvs pdfformaterror 
  105.     % Attempt a retry scan of the element after changing to PDFScanInvNum
  106.     << /PDFScanInvNum true >> setuserparams
  107.     =string cvs
  108.     token pop exch pop dup type
  109.     dup /integertype eq exch /realtype eq or {
  110.       exch pop exch pop
  111.       (', processed as number, value: ) pdfformaterror
  112.       dup =string cvs pdfformaterror (\n) pdfformaterror
  113.      << /PDFScanInvNum null >> setuserparams    % reset to default scanning rules
  114.       false     % suppress any stack cleanup
  115.     } {
  116.       % error was non-recoverable with modified scanning rules
  117.     ('\n) pdfformaterror
  118.       true
  119.     } ifelse
  120.   } {
  121.     true
  122.   } ifelse
  123.   { % clean up the operand stack if this was non-recoverable
  124.   pop pop count exch sub { pop } repeat    % pop all the operands
  125.   } if
  126. } bind def
  127. /.pdfexectoken {        % <count> <opdict> <exectoken> .pdfexectoken ?
  128.   PDFDEBUG {
  129.     pdfdict /PDFSTEPcount known not { pdfdict /PDFSTEPcount 1 .forceput } if
  130.     PDFSTEP {
  131.       pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput
  132.       PDFSTEPcount 1 gt {
  133.     pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput
  134.       } {
  135.         dup ==only
  136.         (    step # ) print PDFtokencount =only 
  137.     ( ? ) print flush 1 false .outputpage
  138.     (%stdin) (r) file 255 string readline {
  139.       token {
  140.             exch pop pdfdict /PDFSTEPcount 3 -1 roll .forceput
  141.       } {
  142.         pdfdict /PDFSTEPcount 1 .forceput
  143.       } ifelse % token
  144.     } {
  145.       pop /PDFSTEP false def     % EOF on stdin
  146.     } ifelse % readline
  147.       } ifelse % PDFSTEPcount > 1
  148.     } {
  149.       dup ==only () = flush
  150.     } ifelse % PDFSTEP
  151.   } if % PDFDEBUG
  152.   2 copy .knownget {
  153.     exch pop exch pop exch pop exec
  154.   } {
  155.         % Normally, true, false, and null would appear in opdict
  156.         % and be treated as "operators".  However, there is a
  157.         % special fast case in the PostScript interpreter for names
  158.         % that are defined in, and only in, systemdict and/or
  159.         % userdict: putting these three names in the PDF dictionaries
  160.         % destroys this property for them, slowing down their
  161.         % interpretation in all PostScript code.  Therefore, we
  162.         % check for them explicitly here instead.
  163.     dup dup dup /true eq exch /false eq or exch /null eq or {
  164.       exch pop exch pop //systemdict exch get
  165.     } {
  166.       % Hackish fix to detect missing whitespace after "endobj". Yet another
  167.       % problem that (you guessed it!) Adobe Acrobat ignores silently
  168.       256 string cvs (endobj) anchorsearch {
  169.         (   **** Missing whitespace after 'endobj'.\n) pdfformaterror
  170.         exch pop cvn get exch pop exec
  171.       } {
  172.         .pdftokenerror
  173.       } ifelse
  174.     } ifelse
  175.   } ifelse
  176. } bind def
  177. /PDFScanRules_true << /PDFScanRules true >> def
  178. /PDFScanRules_null << /PDFScanRules null >> def
  179. /.pdfrun {            % <file> <opdict> .pdfrun -
  180.     % Construct a procedure with the stack depth, file and opdict
  181.     % bound into it.
  182.   1 index cvlit count 2 sub 3 1 roll mark
  183.   /PDFScanRules .getuserparam //null eq {
  184.     //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
  185.     mark 7 4 roll
  186.   } {
  187.     mark 5 2 roll
  188.   } ifelse
  189.   {    % Stack: ..operands.. count opdict file
  190.     { token } stopped {
  191.       dup type /filetype eq { pop } if % pop the operand if it is restored
  192.       (   **** Error reading a content stream. The page may be incomplete.\n)
  193.       pdfformaterror
  194.       //false
  195.     } if {
  196.       dup type /nametype eq {
  197.     dup xcheck {
  198.       .pdfexectoken
  199.     } {
  200.       .pdffixname
  201.       exch pop exch pop PDFDEBUG {
  202.             PDFSTEPcount 1 le {
  203.               dup ==only ( ) print flush
  204.             } if
  205.           } if
  206.     } ifelse
  207.       } {
  208.     exch pop exch pop PDFDEBUG {
  209.           PDFSTEPcount 1 le {
  210.             dup ==only ( ) print flush
  211.           } if
  212.         } if
  213.       } ifelse
  214.     } {
  215.       (%%EOF) cvn cvx .pdfexectoken
  216.     } ifelse
  217.   }
  218.   aload pop .packtomark cvx
  219.   { loop } 0 get 2 packedarray cvx
  220.   { stopped } 0 get
  221.   /PDFScanRules .getuserparam //null eq {
  222.     //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
  223.   } if
  224.   /PDFsource PDFsource
  225.   { store { stop } if } aload pop .packtomark cvx
  226.   /PDFsource 3 -1 roll store exec
  227. } bind def
  228.  
  229. % Execute a file, like .pdfrun, for a marking context.
  230. % This temporarily rebinds LocalResources and DefaultQstate.
  231. /.pdfruncontext {        % <resdict> <file> <opdict> .pdfruncontext -
  232.   /.pdfrun load LocalResources DefaultQstate
  233.   /LocalResources 7 -1 roll store
  234.   /DefaultQstate qstate store
  235.   3 .execn
  236.   /DefaultQstate exch store
  237.   /LocalResources exch store
  238. } bind def
  239.  
  240. % Get the depth of the PDF operand stack.  The caller sets pdfemptycount
  241. % before calling .pdfrun or .pdfruncontext.  It is initially set by
  242. % pdf_main, and is also set by any routine which changes the operand
  243. % stack depth (currently .pdfpaintproc, although there are other callers
  244. % of .pdfrun{context} which have not been checked for opstack depth.
  245. /.pdfcount {        % - .pdfcount <count>
  246.   count pdfemptycount sub
  247. } bind def
  248.  
  249. % Read a token, but simply return false (no token read) in the case of an
  250. % error.  This is messy because 'token' either may or may not pop its operand
  251. % if an error occurs, and because the return values are different depending
  252. % on whether the source is a file or a string. To avoid closing the file
  253. % check for '{' before trying 'token'.
  254. /token_nofail_dict mark
  255.   ( )  { dup ( ) readstring pop pop } bind
  256.   (\t) 1 index
  257.   (\r) 1 index
  258.   (\n) 1 index
  259.   (\000) 1 index
  260.   ({) { //null //true exit } bind
  261. .dicttomark def
  262.  
  263. /token_nofail {        % <file|string> token_nofail false
  264.             % <file> token_nofail <token> true
  265.             % <string> token_nofail <post> <token> true
  266.   dup type /filetype eq {
  267.     { dup ( ) .peekstring not { ({) } if
  268.       //token_nofail_dict exch .knownget not {
  269.         //null 1 index { token } .internalstopped exit
  270.       } if
  271.       exec
  272.     } loop
  273.     {                                   % stack: source null [source]
  274.       //null ne { pop } if pop //false
  275.     } {                         % stack: source null ([post] token true | false)
  276.       { 3 1 roll pop pop //true }
  277.       { pop pop //false }
  278.       ifelse
  279.     } ifelse
  280.   } {
  281.     //null 1 index            % stack: source null source
  282.     { token } .internalstopped {    % stack: source null [source]
  283.       //null ne { pop } if pop //false
  284.     } {                         % stack: source null ([post] token true | false)
  285.       { 4 2 roll pop pop //true }
  286.       { pop pop //false }
  287.       ifelse
  288.     } ifelse
  289.    } ifelse
  290. } bind def
  291.  
  292. currentdict /token_nofail_dict .undef
  293.  
  294. % ================================ Objects ================================ %
  295.  
  296. % Since we may have more than 64K objects, we have to use a 2-D array to
  297. % hold them (and the parallel Generations structure).
  298. /lshift 9 def
  299. /lnshift lshift neg def
  300. /lsubmask 1 lshift bitshift 1 sub def
  301. /lsublen lsubmask 1 add def
  302. /larray {    % - larray <larray>
  303.   [ [] ]
  304. } bind def
  305. /lstring {    % - lstring <lstring>
  306.   [ () ]
  307. } bind def
  308. /ltype {    % <lseq> type <type>
  309.   0 get type
  310. } bind def
  311. /lget {        % <lseq> <index> lget <value>
  312.   dup //lsubmask and 3 1 roll //lnshift bitshift get exch get
  313. } bind def
  314. /lput {        % <lseq> <index> <value> lput -
  315.   3 1 roll
  316.   dup //lsubmask and 4 1 roll //lnshift bitshift get
  317.   3 1 roll put
  318. } bind def
  319. /llength {    % <lseq> llength <length>
  320.   dup length 1 sub dup //lshift bitshift
  321.   3 1 roll get length add
  322. } bind def
  323. % lgrowto assumes newlength > llength(lseq)
  324. /growto {    % <string/array> <length> growto <string'/array'>
  325.   1 index type /stringtype eq { string } { array } ifelse
  326.   2 copy copy pop exch pop
  327. } bind def
  328. /lgrowto {    % <lseq> <newlength> lgrowto <lseq'>
  329.     dup //lsubmask add //lnshift bitshift dup 3 index length gt {
  330.     % Add more sub-arrays.  Start by completing the last existing one.
  331.         % Stack: lseq newlen newtoplen
  332.     3 -1 roll dup llength 1 sub //lsubmask or 1 add lgrowto
  333.         % Stack: newlen newtoplen lseq
  334.     [ exch aload pop
  335.     counttomark 2 add -1 roll        % newtoplen
  336.     counttomark sub { dup 0 0 getinterval lsublen growto } repeat
  337.     dup 0 0 getinterval ] exch
  338.   } {
  339.     pop
  340.   } ifelse
  341.     % Expand the last sub-array.
  342.   1 sub //lsubmask and 1 add
  343.   exch dup dup length 1 sub 2 copy
  344.         % Stack: newsublen lseq lseq len-1 lseq len-1
  345.   get 5 -1 roll growto put
  346. } bind def
  347. /lforall {    % <lseq> <proc> lforall -
  348.   /forall cvx 2 packedarray cvx forall
  349. } bind def
  350.  
  351. % We keep track of PDF objects using the following PostScript variables:
  352. %
  353. %    Generations (lstring): Generations[N] holds 1+ the current
  354. %        generation number for object number N.  (As far as we can tell,
  355. %        this is needed only for error checking.)  For free objects,
  356. %        Generations[N] is 0.
  357. %
  358. %    Objects (larray): If object N is loaded, Objects[N] is the actual
  359. %        object; otherwise, Objects[N] is an executable integer giving
  360. %        the file offset of the object's location in the file.  If
  361. %        ObjectStream[N] is non-zero then Objects[N] contains the index
  362. %        into the object stream instead of the file offset of the object.
  363. %
  364. %    ObjectStream (larray): If object N is in an object stream then
  365. %        ObjectStream[N] holds the object number of the object stream.
  366. %        Otherwise ObjectStream[N] contains 0.  If ObjectStream[N]
  367. %        is non-zero then Objects[N] contains  the index into the object
  368. %        stream.
  369. %
  370. %    GlobalObjects (dictionary): If object N has been resolved in
  371. %        global VM, GlobalObjects[N] is the same as Objects[N]
  372. %        (except that GlobalObjects itself is stored in global VM,
  373. %        so the entry will not be deleted at the end of the page).
  374. %
  375. %    IsGlobal (lstring): IsGlobal[N] = 1 iff object N was resolved in
  376. %        global VM.  This is an accelerator to avoid having to do a
  377. %        dictionary lookup in GlobalObjects when resolving every object.
  378.  
  379. % Initialize the PDF object tables.
  380. /initPDFobjects {        % - initPDFobjects -
  381.   /ObjectStream larray def
  382.   /Objects larray def
  383.   /Generations lstring def
  384.   .currentglobal true .setglobal
  385.   /GlobalObjects 20 dict def
  386.   .setglobal
  387.   /IsGlobal lstring def
  388. } bind def
  389.  
  390. % Grow the tables to a specified size.
  391. /growPDFobjects {        % <minsize> growPDFobjects -
  392.   dup ObjectStream llength gt {
  393.     dup ObjectStream exch lgrowto /ObjectStream exch def
  394.   } if
  395.   dup Objects llength gt {
  396.     dup Objects exch lgrowto /Objects exch def
  397.   } if
  398.   dup Generations llength gt {
  399.     dup Generations exch lgrowto /Generations exch def
  400.   } if
  401.   dup IsGlobal llength gt {
  402.     dup IsGlobal exch lgrowto /IsGlobal exch def
  403.   } if
  404.   pop
  405. } bind def
  406.  
  407. % We represent an unresolved object reference by a procedure of the form
  408. % {obj# gen# resolveR}.  This is not a possible PDF object, because PDF has
  409. % no way to represent procedures.  Since PDF in fact has no way to represent
  410. % any PostScript object that doesn't evaluate to itself, we can 'force'
  411. % a possibly indirect object painlessly with 'exec'.
  412. % Note that since we represent streams by executable dictionaries
  413. % (see below), we need both an xcheck and a type check to determine
  414. % whether an object has been resolved.
  415. /resolved? {        % <object#> resolved? <value> true
  416.             % <object#> resolved? false
  417.   Objects 1 index lget dup xcheck {    % Check if executable
  418.     dup type /integertype eq {        % Check if an integer
  419.         % Check whether the object is in GlobalObjects.
  420.       pop IsGlobal 1 index lget 0 eq {    % 0 --> Not in GlabalObjects
  421.     pop false            % The object is not resolved
  422.       } {                % The object is in GlobalObjects
  423.         % Update Objects from GlobalObjects
  424.     PDFDEBUG { (%Global=>local: ) print dup == } if
  425.     GlobalObjects 1 index get dup Objects 4 1 roll lput true
  426.       } ifelse
  427.     } {                % Else object is executable but not integer
  428.       exch pop true        % Therefore must be executable dict. (stream)
  429.     } ifelse
  430.   } {                % Else object is not executable.
  431.     exch pop true        % Therefore it must have been resolved.
  432.   } ifelse
  433. } bind def
  434. /oforce /exec load def
  435. /oget {        % <array> <index> oget <object>
  436.         % <dict> <key> oget <object>
  437.         % Before release 6.20, this procedure stored the resolved
  438.         % object back into the referring slot.  In order to support
  439.         % PDF linearization, we no longer do this.
  440.   get oforce
  441. } bind def
  442. /oforce_array { % <array> oforce_array <array>
  443.   [ exch { oforce } forall ]
  444. } bind def
  445. /oforce_elems { % <array> oforce_elems <first> ... <last>
  446.   { oforce } forall
  447. } bind def
  448. /oforce_recursive { % <any> oforce_recursive <any>
  449.   oforce dup type dup /arraytype eq {
  450.     pop [ exch { oforce_recursive } forall ]
  451.   } {
  452.     /dicttype eq {
  453.      << exch { oforce_recursive exch oforce exch } forall >> 
  454.     } if
  455.   } ifelse
  456. } bind def
  457.  
  458. % A null value in a dictionary is equivalent to an omitted key;
  459. % we must check for this specially.
  460. /knownoget {    % <dict> <key> knownoget <value> true
  461.         % <dict> <key> knownoget false
  462.         % See oget above regarding this procedure.
  463.   .knownget {
  464.     oforce dup //null eq { pop //false } { //true } ifelse
  465.   } {
  466.     //false
  467.   } ifelse
  468. } bind def
  469.  
  470. /knownogetdict { % <dict> <key> knownogetdict <dict> true
  471.          % <dict> <key> knownogetdict false
  472.   //knownoget exec dup {
  473.     1 index type /dicttype ne { pop pop //false } if
  474.   } if
  475. } bind def
  476.  
  477.  
  478. % PDF 1.1 defines a 'foreign file reference', but not its meaning.
  479. % Per the specification, we convert these to nulls.
  480. /F {        % <file#> <object#> <generation#> F <object>
  481.         % Some PDF 1.1 files use F as a synonym for f!
  482.    .pdfcount 3 lt { f } { pop pop pop null } ifelse
  483. } bind def
  484.  
  485. % Verify the generation number for a specified object
  486. % Note:  The values in Generations is the generation number plus 1.
  487. % If the value in Generations is zero then the object is free.
  488. /checkgeneration {  % <object#> <generation#> checkgeneration <object#> <OK>
  489.   Generations 2 index lget 1 sub 1 index eq {    % If generation # match ...
  490.     pop true                    % Then return true
  491.   } {                    % Else not a match ...
  492.     QUIET not {                % Create warning message if not QUIET
  493.       Generations 2 index lget 0 eq {    % Check if object is free ...
  494.     (   **** Warning: reference to free object: )
  495.         2 index =string cvs concatstrings ( ) concatstrings    % put obj #
  496.         exch =string cvs concatstrings ( R\n) concatstrings    % put gen #
  497.       } {
  498.     (   **** Warning: wrong generation: )
  499.         2 index =string cvs concatstrings ( ) concatstrings    % put obj #
  500.         exch =string cvs concatstrings                % put gen #
  501.            (, xref gen#: ) concatstrings 1 index Generations  % put xref gen #
  502.            exch lget 1 sub =string cvs concatstrings (\n) concatstrings
  503.       } ifelse
  504.       pdfformaterror            % Output warning message
  505.     } {                    % Else QUIET ...
  506.       pop                % Pop generation number
  507.     } ifelse
  508.     % We should return false for an incorrect generation number, however
  509.     % we are simply printing a warning and then returning true.  This makes
  510.     % Ghostscript tolerant of of bad generation numbers.
  511.     true
  512.   } ifelse
  513. } bind def
  514. /R {        % <object#> <generation#> R <object>
  515.   /resolveR cvx 3 packedarray cvx
  516. } bind def
  517.  
  518. % If we encounter an object definition while reading sequentially,
  519. % we just store it away and keep going.
  520. /objopdict mark
  521.   valueopdict { } forall
  522.   /endobj dup cvx
  523. .dicttomark readonly def
  524.  
  525. /obj {            % <object#> <generation#> obj <object>
  526.   PDFfile objopdict .pdfrun
  527. } bind def
  528.  
  529. /endobj {        % <object#> <generation#> <object> endobj <object>
  530.   3 1 roll
  531.         % Read the xref entry if we haven't yet done so.
  532.         % This is only needed for generation # checking.
  533.   1 index resolved? {
  534.     pop
  535.   } if
  536.   checkgeneration {
  537.         % The only global objects we bother to save are
  538.         % (resource) dictionaries.
  539.     1 index dup gcheck exch type /dicttype eq and {
  540.       PDFDEBUG { (%Local=>global: ) print dup == } if
  541.       GlobalObjects 1 index 3 index put
  542.       IsGlobal 1 index 1 put
  543.     } if
  544.     Objects exch 2 index lput
  545.   } {
  546.     pop pop null
  547.   } ifelse
  548. } bind def
  549.  
  550. % When resolving an object reference in an object stream, we stop at
  551. % the end of file.  Note:  Objects in an object stream do not have either
  552. % a starting 'obj' or and ending 'endobj'.
  553. /resolveobjstreamopdict mark
  554.   valueopdict { } forall
  555.   (%%EOF) cvn { exit } bind
  556.   /endobj {  % bug 689795
  557.     (   **** Warning: Objects in an object stream should not have 'endobj'.\n)
  558.     pdfformaterror
  559.   } bind
  560. .dicttomark readonly def
  561.  
  562. % Note: This version of this function is not currently being used.
  563. % Resolve all objects in an object stream
  564. /resolveobjectstream {        % <object stream #> resolveobjectstream -
  565.   PDFDEBUG { (%Resolving object stream: ) print } if
  566.   0 resolveR    % Get the objectstream dict, all objstrms use 0 as the gen #
  567.   dup /First get        % Save location of first object onto the stack
  568.   1 index /N get        % Save number of objects onto the stack
  569.   2 index false resolvestream    % Convert stream dict into a stream
  570.   /ReusableStreamDecode filter    % We need to be able to position stream
  571.         % Objectstreams begin with list of object numbers and locations
  572.         % Create two arrays to hold object numbers and stream location
  573.   1 index array            % Array for holding object number
  574.   2 index array            % Array for holding stream object location
  575.         % Get the object numbers and locations.
  576.   0 1 5 index 1 sub {        % Loop and collect obj # and locations
  577.         % Stack: objstreamdict First N objectstream [obj#] [loc] index
  578.     2 index 1 index         % Setup to put obj# into object number array
  579.     5 index token pop put    % Get stream, then get obj# and put into array
  580.     1 index 1 index         % Setup to put object loc into location array
  581.     5 index token pop put    % Get stream, get obj loc and put into array
  582.     pop                % Remove loop index
  583.   } for
  584.           % Create a bytestring big enough for reading any object data
  585.           % Scan for the size of the largest object
  586.   0 0                % Init max object size and previous location
  587.   2 index {            % Loop through all object locations
  588.                 % Stack:  ... maxsize prevloc currentloc
  589.     dup 4 1 roll        % Save copy of object location into stack
  590.     exch sub                % Object size = currentloc - prevloc
  591.     .max            % Determine maximum object size
  592.     exch            % Put max size under previous location
  593.   } forall
  594.   pop                % Remove previous location
  595.   .bigstring            % Create bytestring based upon max obj size
  596.         % Move to the start of the object data
  597.   3 index 6 index        % Get objectstream and start of first object
  598.   setfileposition        % Move to the start of the data
  599.           % Read the data for all objects except the last.  We do
  600.         % not know the size of the last object so we need to treat
  601.         % it as a special case.
  602.   0 1 6 index 2 sub {
  603.     dup 4 index exch get     % Get our current object number
  604.         % Stack: objstreamdict First N objectstream [obj#] [loc]
  605.         %        bytestring loopindex object#
  606.     dup resolved? {        % If we already have this object
  607.         (yyy) = pstack (yyy) = flush xxx
  608.       pop pop            % Remove object and object number
  609.       1 add 2 index exch get    % Get location of next object
  610.       6 index add 6 index exch    % Form location of next object and get stream
  611.       setfileposition        % Move to the start of the next object data
  612.     } {                % Else this is a new object ...
  613.         % We are going to create a string for reading the object
  614.       2 index 0            % use our working string
  615.           % Determine the size of the object
  616.       5 index 4 index 1 add get    % Get location of the next object
  617.       6 index 5 index get    % Get location of this object
  618.       sub            % Size of object = next loc - this loc
  619.       getinterval        % Create string for reading object
  620.       6 index exch readstring pop    % Read object
  621.       /ReusableStreamDecode filter     % Convert string into a stream
  622.       resolveobjstreamopdict .pdfrun    % Get PDF object
  623.       Objects exch 2 index exch lput     % Put object into Objects array
  624.       pop pop            % Remove object # and loop index
  625.     } ifelse
  626.   } for
  627.   pop pop            % Remove our working string and loc array
  628.           % Now read the last object in the object stream.  Since it
  629.         % is the last object, we can use the original stream and
  630.         % terminate when we hit the end of the stream
  631.         % Stack: objstreamdict First N objectstream [obj#]
  632.   2 index 1 sub get         % Get our current object number
  633.   dup resolved? not {        % If we do not already have this object
  634.     exch             % Get our object stream
  635.     resolveobjstreamopdict .pdfrun    % Get PDF object
  636.     Objects exch 2 index exch lput    % Put object into Objects array
  637.   } if
  638.   pop pop pop pop        % Clear stack
  639. } bind def
  640.  
  641. /no_debug_dict <<
  642.   /PDFDEBUG false
  643. >> readonly def
  644.  
  645. % Resolve all objects in an object stream
  646. /resolveobjectstream {        % <object stream #> resolveobjectstream -
  647.   PDFDEBUG { (%Resolving object stream: ) print } if
  648.   dup 0 resolveR % Get the objectstream dict, all objstrms use 0 as the gen #
  649.   dup /Type get /ObjStm ne {    % Verify type is object stream
  650.     (   **** Incorrect Type in object stream dictionary.\n) pdfformaterror
  651.     /resolveobjectstream cvx /typecheck signalerror
  652.   } if
  653.   dup /N get            % Save number of objects onto the stack
  654.   1 index false resolvestream    % Convert stream dict into a stream
  655.   /ReusableStreamDecode filter    % We need to be able to position stream
  656.         % Objectstreams begin with list of object numbers and locations
  657.   1 index array            % Create array for holding object number
  658.         % Get the object numbers
  659.   0 1 4 index 1 sub {        % Loop and collect obj numbers
  660.         % Stack: strm# objstreamdict N PDFDEBUG objectstream [obj#] loopindex
  661.     1 index 1 index         % Setup to put obj# into object number array
  662.     4 index token pop put    % Get stream, then get obj# and put into array
  663.     2 index token pop pop pop    % Get stream, get obj loc and clear stack
  664.   } for
  665.         % Move to the start of the object data
  666.   1 index 4 index /First get    % Get objectstream and start of first object
  667.   setfileposition        % Move to the start of the data
  668.           % We disable PDFDEBUG while reading the data stream.  We will
  669.         % print the data later
  670.   PDFDEBUG { //no_debug_dict begin } if
  671.           % Read the data for all objects.  We check to see if we get
  672.         % the number of objects that we expect.
  673.         % Stack: strm# objstreamdict N objectstream [obj#] PDFDEBUG
  674.   mark 3 -1 roll         % Get objectstream
  675.   count 4 index add        % Determine stack depth with objects
  676.   3 1 roll
  677.   resolveobjstreamopdict .pdfrun % Get PDF objects
  678.   count counttomark 1 add index ne { % Check stack depth
  679.     (   **** Incorrect object count in object stream.\n) pdfformaterror
  680.     /resolveobjectstream cvx /rangecheck signalerror
  681.   } if
  682.           % We have the object data
  683.   counttomark array astore    % Put objects into an array
  684.   exch pop exch pop        % Remove mark and count
  685.   currentdict //no_debug_dict eq { end } if % Restore debug context
  686.         % Save the objects into Objects
  687.   0 1 2 index length 1 sub {    % Loop through all objects
  688.         % Stack: strm# objstreamdict N [obj#] [objects] loopindex
  689.     dup 3 index exch get     % Get our current object number
  690.                 % Stack: strm# objstreamdict N [obj#] [objects] loopindex obj#
  691.     dup ObjectStream exch lget 7 index eq {
  692.       dup resolved? {        % If we already have this object
  693.         pop pop            % Remove object and object number
  694.       } {            % Else if we do not have this object
  695.         PDFDEBUG { (%Resolving compressed object: [) print dup =only ( 0]) = } if
  696.         Objects exch 3 index    % Put the object into Objects
  697.         3 index get
  698.         PDFDEBUG { dup === flush } if
  699.         lput
  700.       } ifelse
  701.     } {
  702.       pop    % Ignore old object; remove object number.
  703.     } ifelse
  704.     pop             % Remove loop index
  705.   } for
  706.   pop pop pop pop pop        % Remove strm# objstream, N, (obj#], and [objects]
  707. } bind def
  708.  
  709. currentdict /no_debug_dict undef
  710.  
  711. % When resolving an object reference, we stop at the endobj or endstream.
  712. /resolveopdict mark
  713.   valueopdict { } forall
  714.   /endstream { endobj exit } bind
  715.   /endobj { endobj exit } bind
  716.   /endjobj { % Bug 689876.
  717.      (   **** Operator 'endobj' is misspelled as 'endjobj'.\n) pdfformaterror
  718.      endobj exit
  719.   } bind
  720.                 % OmniForm generates PDF file with endobj missing in some
  721.                 % objects. AR ignores this. So we have to do it too.
  722.   /obj { pop pop endobj exit } bind
  723. .dicttomark readonly def
  724.  
  725. /resolveR {        % <object#> <generation#> resolveR <object>
  726.   PDFDEBUG {
  727.     PDFSTEPcount 1 le {
  728.       (%Resolving: ) print 2 copy 2 array astore ==
  729.     } if
  730.   } if
  731.   1 index resolved? {        % If object has already been resolved ...
  732.     exch pop exch pop        % then clear stack and return object
  733.   } {                % Else if not resolved ...
  734.     PDFfile fileposition 3 1 roll    % Save current file position
  735.     1 index Objects exch lget        % Get location of object from xref
  736.     3 1 roll checkgeneration {        % Verify the generation number
  737.             % Stack: savepos objpos obj#
  738.        ObjectStream 1 index lget dup 0 eq { % Check if obj in not an objstream
  739.      pop exch PDFoffset add PDFfile exch setfileposition
  740.      PDFfile token pop 2 copy ne
  741.       { (   **** Unrecoverable error in xref!\n) pdfformaterror
  742.         /resolveR cvx /rangecheck signalerror
  743.       }
  744.      if pop PDFfile token pop
  745.      PDFfile token pop /obj ne
  746.       { (   **** Unrecoverable error in xref!\n) pdfformaterror
  747.         /resolveR cvx /rangecheck signalerror
  748.       }
  749.      if
  750.      pdf_run_resolve    % PDFfile resolveopdict .pdfrun
  751.       } {            % Else the object is in an ObjectStream
  752.               % Process an objectstream object.  We are going to resolve all
  753.               % of the objects in sthe stream and place them into the Objects
  754.               % array.
  755.         % Stack: savepos objpos obj# objectstream#
  756.     resolveobjectstream
  757.         resolved? {        % If object has already been resolved ...
  758.       exch pop        % Remove object pos from stack.
  759.     } {
  760.       pop pop null        % Pop objpos and obj#, put null for object
  761.     } ifelse
  762.       } ifelse
  763.     } {                % Else the generation number is wrong
  764.         % Don't cache if the generation # is wrong.
  765.     pop pop null        % Pop objpos and obj#, put null for object
  766.     } ifelse            % ifelse generation number is correct
  767.     exch PDFfile exch setfileposition    % Return to original file position
  768.   } ifelse
  769. } bind def      
  770.  
  771. % ================================ Streams ================================ %
  772.  
  773. % We represent a stream by an executable dictionary that contains,
  774. % in addition to the contents of the original stream dictionary:
  775. %    /File - the file or string where the stream contents are stored,
  776. %      if the stream is not an external one.
  777. %    /FilePosition - iff File is a file, the position in the file
  778. %      where the contents start.
  779. %    /StreamKey - the key used to decrypt this stream, if any.
  780. % We do the real work of constructing the data stream only when the
  781. % contents are needed.
  782.  
  783. % Construct a stream.  The length is not reliable in the face of
  784. % different end-of-line conventions, but it's all we've got.
  785. %
  786. % PDF files are inconsistent about what may fall between the 'stream' keyword
  787. % and the actual stream data, and it appears that no one algorithm can
  788. % detect this reliably.  We used to try to guess whether the file included
  789. % extraneous \r and/or \n characters, but we no longer attempt to do so,
  790. % especially since the PDF 1.2 specification states flatly that the only
  791. % legal terminators following the 'stream' keyword are \n or \r\n, both of
  792. % which are properly skipped and discarded by the token operator.
  793. % Unfortunately, this doesn't account for other whitespace characters that
  794. % may have preceded the EOL, such as spaces or tabs. Thus we back up one
  795. % character and scan until we find the \n terminator.
  796. /stream {    % <dict> stream <modified_dict>
  797.   dup /Length oget 0 eq {
  798.     dup /Filter undef    % don't confuse any filters that require data
  799.   } if
  800.   dup /F known dup PDFsource PDFfile eq or {
  801.     not {
  802.       dup /File PDFfile put
  803.       % make sure that we are just past the EOL \n character
  804.       PDFfile dup fileposition 1 sub setfileposition    % back up one
  805.  
  806.       PDFfile read pop
  807.       dup 13 eq {
  808.         % If there had been a \n, token would have advanced over it
  809.     % thus, if the terminator was \r, we have a format error!
  810.     (   **** Warning: stream operator not terminated by valid EOL.\n) pdfformaterror
  811.     pop   % fileposition is OK (just past the \r).
  812.       } {
  813.         % Otherwise, scan past \n
  814.         { 10 eq { exit } if
  815.           PDFfile read pop
  816.         } loop
  817.       } ifelse   
  818.       dup /FilePosition PDFfile fileposition put
  819.       PDFDEBUG {
  820.         PDFSTEPcount 1 le {
  821.           (%FilePosition: ) print dup /FilePosition get ==
  822.         } if
  823.       } if
  824.     } if
  825.     % Some (bad) PDf files have invalid stream lengths.  This causes problems
  826.     % if we reposition beyond the end of the file.  So we compare the given
  827.     % length to number of bytes left in the file.
  828.     dup /Length oget 
  829.     dup PDFfile bytesavailable lt {    % compare to to bytes left in file
  830.       PDFfile fileposition         % reposition to the end of stream
  831.       add PDFfile exch setfileposition
  832.     } {
  833.       pop                % bad stream length - do not reposition.
  834.                           % This will force a length warning below
  835.     } ifelse
  836.   } {
  837.     pop
  838.     % We're already reading from a stream, which we can't reposition.
  839.     % Capture the sub-stream contents in a string.
  840.     dup /Length oget string PDFsource exch readstring
  841.     not {
  842.       (   **** Warning: Unexpected EOF in stream!\n) pdfformaterror
  843.       /stream cvx /rangecheck signalerror
  844.     } if
  845.     1 index exch /File exch put
  846.   } ifelse
  847.   PDFsource token_nofail not { //null } if
  848.   dup /endobj eq {
  849.     % Another case that Acrobat Reader handles -- 'endobj' without 'endstream'.
  850.     (   **** Warning: stream missing 'endstream'.\n) pdfformaterror
  851.     pop /endstream        % fake a valid endstream
  852.   } if
  853.   /endstream ne { 
  854.     (   **** Warning: stream Length incorrect.\n) pdfformaterror
  855.     dup /Length undef % prevent the use of the incorrect length.
  856.     cvx endobj exit   % exit from .pdfrun now.
  857.   } {
  858.     PDFsource (??) .peekstring pop (>>) eq { % Bug 690161, sample #1
  859.       (   **** Warning: Spurious '>>' after 'endstream' ignored.\n) pdfformaterror
  860.       PDFsource (12) readstring pop pop
  861.     } if
  862.   } ifelse
  863.   cvx
  864. } bind def
  865. /endstream {
  866.   exit
  867. } bind def
  868.  
  869. % Contrary to the published PDF (1.3) specification, Acrobat Reader
  870. % accepts abbreviated filter names everywhere, not just for in-line images,
  871. % and some applications (notably htmldoc) rely on this.
  872. /unabbrevfilterdict mark
  873.   /AHx /ASCIIHexDecode  /A85 /ASCII85Decode  /CCF /CCITTFaxDecode
  874.   /DCT /DCTDecode  /Fl /FlateDecode  /LZW /LZWDecode  /RL /RunLengthDecode
  875. .dicttomark readonly def
  876.  
  877. % Extract and apply filters.
  878. /filterparms {        % <dict> <DPkey> <Fkey> filterparms
  879.             %   <dict> <parms> <filternames>
  880.   2 index exch knownoget {
  881.     oforce_recursive
  882.     exch 2 index exch knownoget {
  883.         % Both filters and parameters.
  884.       oforce_recursive
  885.       exch dup type /nametype eq {
  886.     1 array astore exch
  887.     dup type /arraytype ne { 1 array astore } if exch
  888.       } if
  889.     } {
  890.         % Filters, but no parameters.
  891.       //null exch
  892.       dup type /nametype eq { 1 array astore } if
  893.     } ifelse
  894.   } {
  895.         % No filters: ignore parameters, if any.
  896.     pop //null { }
  897.   } ifelse
  898. } bind def
  899. /filtername {        % <filtername> filtername <filtername'>
  900.   //unabbrevfilterdict 1 index .knownget { exch pop } if
  901.   dup /Filter resourcestatus { pop pop } {
  902.     Repaired exch    % this error is not the creator's fault    
  903.     (   **** ERROR: Unable to process ) pdfformaterror
  904.     64 string cvs pdfformaterror
  905.     ( data. Page will be missing data.\n) pdfformaterror
  906.     /Repaired exch store % restore the previous "Repaired" state
  907.     % provide a filter that returns EOF (no data)
  908.     /.EOFDecode
  909.   } ifelse
  910. } bind def
  911. /applyfilters {        % <parms> <source> <filternames> applyfilters <stream>
  912.   2 index null eq {
  913.     { filtername filter }
  914.   } {
  915.     {        % Stack: parms source filtername
  916.       2 index 0 oget dup null eq { pop } {
  917.         exch filtername dup /JBIG2Decode eq { exch jbig2cachectx exch } if
  918.       } ifelse filter
  919.       exch dup length 1 sub 1 exch getinterval exch
  920.     }
  921.   } ifelse forall exch pop
  922. } bind def
  923.  
  924. % JBIG2 streams have an optional 'globals' stream obj for
  925. % sharing redundant data between page images. Here we resolve
  926. % that stream reference (if any) and run it through the decoder,
  927. % creating a special -jbig2globalctx- postscript object our
  928. % JBIG2Decode filter implementation looks for in the parm dict.
  929. /jbig2cachectx { % <parmdict> jbig2cachectx <parmdict>
  930.   dup /JBIG2Globals knownoget {
  931.     % make global ctx
  932.     PDFfile fileposition exch % resolvestream is not reentrant
  933.     true resolvestream         % stack after: PDFfileposition -file-
  934.     % Read the data in a loop until EOF to so we can move the strings into a bytestring
  935.     [ { counttomark 1 add index 60000 string readstring not { exit } if } loop ]
  936.     exch pop 0 1 index { length add } forall    % compute the total length
  937.     % now copy the data from the array of strings into a bytestring
  938.     .bytestring exch 0 exch { 3 copy putinterval length add } forall pop
  939.     .jbig2makeglobalctx
  940.     PDFfile 3 -1 roll setfileposition
  941.     1 index exch
  942.     /.jbig2globalctx exch put
  943.   } if
  944. } bind def
  945.  
  946. % When used with a PDF image dict, the JPXDecode filter needs to know
  947. % about any ColorSpace entries, since this overrides whatever is in
  948. % the image stream itself. We therefore propagate any such key into
  949. % a filter's DecodeParms.
  950. /jpxparmfix {    % <streamdict> <readdata?> jpxparmfix <streamdict <readdata?>
  951.   1 index /Filter .knownget
  952.     { /JPXDecode eq % we only need to do this for JPXDecode filters
  953.     % TODO: handle filter arrays
  954.       {
  955.     1 index /ColorSpace knownoget {
  956.       2 index /DecodeParms knownoget {
  957.         % insert in the existing DecodeParms dict
  958.         /ColorSpace 3 -1 roll put
  959.       }{
  960.         1 dict % need to create a custom DecodeParms dict
  961.         dup /ColorSpace 4 -1 roll put
  962.         2 index exch /DecodeParms exch put
  963.       } ifelse
  964.     } if
  965.       } if
  966.     } if
  967. } bind def
  968.  
  969. % Resolve a stream dictionary to a PostScript stream.
  970. % Streams with no filters require special handling:
  971. %     - Whether we are going to interpret the stream, or If we are just
  972. %       going to read data from them, we impose a SubFileDecode filter
  973. %         that reads just the requisite amount of data.
  974. % Note that, in general, resolving a stream repositions PDFfile.
  975. % Clients must save and restore the position of PDFfile themselves.
  976. /resolvestream {    % <streamdict> <readdata?> resolvestream <stream>
  977.   jpxparmfix
  978.   1 index /F knownoget {
  979.         % This stream is stored on an external file.
  980.     (r) file 3 -1 roll
  981.     /FDecodeParms /FFilter filterparms
  982.         % Stack: readdata? file dict parms filternames
  983.     4 -1 roll exch
  984.     pdf_decrypt_stream
  985.     applyfilters
  986.   } {
  987.     exch
  988.     dup /Length knownoget { 0 eq } { //false } ifelse {
  989.       () 0 () /SubFileDecode filter
  990.     } {
  991.       dup /FilePosition .knownget {
  992.         1 index /File get exch setfileposition
  993.       } if
  994.         % Stack: readdata? dict
  995.       /DecodeParms /Filter filterparms
  996.         % Stack: readdata? dict parms filternames
  997.       2 index /File get exch
  998.         % Stack: readdata? dict parms file/string filternames
  999.       dup length 0 eq {
  1000.         % All the PDF filters have EOD markers, but in this case
  1001.         % there is no specified filter.
  1002.         exch dup type /filetype eq 5 index or {
  1003.               % Use length for any files or reading data from any source.
  1004.           3 index /Length knownoget not { 0 } if
  1005.         } {
  1006.         0       % Otherwise length of 0 for whole string
  1007.         } ifelse
  1008.         4 index /IDFlag known { pop } { () /SubFileDecode filter } ifelse
  1009.         exch
  1010.         pdf_decrypt_stream        % add decryption if needed
  1011.         pop exch pop
  1012.       } {
  1013.                 % Stack: readdata? dict parms source filternames
  1014.         exch 3 index /Length knownoget {
  1015.           () /SubFileDecode filter
  1016.         } if exch
  1017.         pdf_decrypt_stream        % add decryption if needed
  1018.         applyfilters
  1019.       } ifelse
  1020.     } ifelse
  1021.   } ifelse
  1022.         % Stack: readdata? dict file
  1023.   exch pop exch pop
  1024. } bind def
  1025.  
  1026. % ============================ Name/number trees ============================ %
  1027.  
  1028. /nameoget {        % <nametree> <key> nameoget <obj|null>
  1029.   exch /Names exch .treeget
  1030. } bind def
  1031.  
  1032. /numoget {        % <numtree> <key> numoget <obj|null>
  1033.   exch /Nums exch .treeget
  1034. } bind def
  1035.  
  1036. /.treeget {        % <key> <leafkey> <tree> .treeget <obj|null>
  1037.   dup /Kids knownoget {
  1038.     exch pop .branchget
  1039.   } {
  1040.     exch get .leafget
  1041.   } ifelse
  1042. } bind def
  1043.  
  1044. /.branchget {        %  <key> <leafkey> <kids> .branchget <obj|null>
  1045.   dup length 0 eq {
  1046.     pop pop pop null
  1047.   } {
  1048.     dup length -1 bitshift 2 copy oget
  1049.             % Stack: key leafkey kids mid kids[mid]
  1050.     dup /Limits oget aload pop
  1051.             % Stack: key leafkey kids mid kids[mid] min max
  1052.     6 index lt {
  1053.       pop pop
  1054.       1 add 1 index length 1 index sub getinterval .branchget
  1055.     } {
  1056.       5 index gt {
  1057.     pop
  1058.     0 exch getinterval .branchget
  1059.       } {
  1060.     exch pop exch pop .treeget
  1061.       } ifelse
  1062.     } ifelse
  1063.   } ifelse
  1064. } bind def
  1065.  
  1066. /.leafget {        % <key> <pairs> .leafget <obj|null>
  1067.   dup length 2 eq {
  1068.     dup 0 get 2 index eq { 1 oget } { pop null } ifelse
  1069.     exch pop
  1070.   } {
  1071.     dup length -1 bitshift -2 and 2 copy oget
  1072.             % Stack: key pairs mid pairs[mid]
  1073.     3 index gt { 0 exch } { 1 index length 1 index sub } ifelse
  1074.     getinterval .leafget
  1075.   } ifelse
  1076. } bind def
  1077.  
  1078. end            % pdfdict
  1079. .setglobal
  1080.